Skip to content

feat(sdk): add AxonListParams support and auto-pagination to AxonOps.list()#763

Merged
sid-rl merged 1 commit into
nextfrom
sid/oo-sdk-axon-list-params
Apr 1, 2026
Merged

feat(sdk): add AxonListParams support and auto-pagination to AxonOps.list()#763
sid-rl merged 1 commit into
nextfrom
sid/oo-sdk-axon-list-params

Conversation

@sid-rl

@sid-rl sid-rl commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

User description

⚠️ PR Title Must Follow Conventional Commits

Format: feat[optional scope]: <description>

Examples: feat: add new SDK method · feat(storage): support file uploads · feat!: breaking API change


Description

  • Update AxonOps.list() to accept AxonListParams (id, name, limit, starting_after, include_total_count) and auto-paginate via for await
  • Update tests/sdk/axon-ops.test.ts with async-iterable mocks and new filter/options tests

Motivation

Changes

  • src/sdk.ts — import AxonListParams, update AxonOps.list() signature and body
  • tests/sdk/axon-ops.test.ts — rewrite list mocks for for await, add filter params test

Testing

  • Unit tests added
  • Integration tests added
  • Smoke Tests added/updated
  • Tested locally

Breaking Changes

Checklist

  • PR title follows Conventional Commits format (feat: or feat(scope):)
  • Documentation updated (if needed)
  • Breaking changes documented (if applicable)

CodeAnt-AI Description

Add filterable Axon listing with automatic pagination

What Changed

  • Axon lists can now accept filter and limit options when fetching results
  • Listing now returns all available axons across pages instead of only the first page
  • Tests were updated to cover filtering, request options, timeout behavior, and pagination-related polling cases

Impact

✅ Filtered axon lists
✅ Fewer missed axons in large accounts
✅ More reliable SDK list results

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@sid-rl sid-rl changed the title Sid/oo sdk axon list params feat(sdk): add AxonListParams support and auto-pagination to AxonOps.list() Mar 31, 2026
@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Mar 31, 2026
@codeant-ai codeant-ai Bot changed the title feat(sdk): add AxonListParams support and auto-pagination to AxonOps.list() Sid/oo sdk axon list params Mar 31, 2026
@sid-rl sid-rl changed the title Sid/oo sdk axon list params feat(sdk): add AxonListParams support and auto-pagination to AxonOps.list() Mar 31, 2026
Comment on lines +423 to +432
const secretValue = 'test-value-from-gateway';

expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(secretName);
const createResult = await curlRequest('POST', '/v1/secrets', {
body: JSON.stringify({ name: secretName, value: secretValue }),
contentType: 'application/json',
});

test('POST request with JSON body - create blueprint', async () => {
const blueprintName = uniqueName('gateway-test-blueprint');
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(secretName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This test creates a secret through the gateway but never deletes it, which leaks resources across repeated smoke-test runs and can eventually hit account limits. Add cleanup in a finally block so the secret is deleted even after assertions. [resource leak]

Severity Level: Major ⚠️
- ⚠️ Smoketest suite leaks secrets in the connected Runloop account.
- ⚠️ Repeated runs can hit per-account secret quotas/limits.
- ⚠️ Additional manual cleanup needed in long-lived test environments.
Suggested change
const secretValue = 'test-value-from-gateway';
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(secretName);
const createResult = await curlRequest('POST', '/v1/secrets', {
body: JSON.stringify({ name: secretName, value: secretValue }),
contentType: 'application/json',
});
test('POST request with JSON body - create blueprint', async () => {
const blueprintName = uniqueName('gateway-test-blueprint');
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(secretName);
const secretValue = 'test-value-from-gateway');
try {
const createResult = await curlRequest('POST', '/v1/secrets', {
body: JSON.stringify({ name: secretName, value: secretValue }),
contentType: 'application/json',
});
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(secretName);
} finally {
await curlRequest('DELETE', `/v1/secrets/${encodeURIComponent(secretName)}`).catch(() => {});
}
Steps of Reproduction ✅
1. Enable smoketests by setting `RUN_SMOKETESTS=1` so the `comprehensive gateway proxying
tests` suite at `tests/smoketests/object-oriented/gateway-config.test.ts:282` runs.

2. Ensure `RUNLOOP_API_KEY` and (optionally) `RUNLOOP_BASE_URL` are set so the `beforeAll`
in that suite (`lines 331–377`) successfully provisions a gateway config, devbox, and base
secret `testSecretName`.

3. Run the Jest test file `tests/smoketests/object-oriented/gateway-config.test.ts`,
letting the test `POST request - create a secret` at lines 421–433 execute; it calls
`curlRequest` (defined at 291–329) to POST `/v1/secrets` with a unique `secretName`.

4. Observe that after the test assertions on `createResult.httpCode` and `created.name`,
there is no corresponding delete via `sdk.secret.delete` or gateway DELETE request for
`secretName`; repeated smoketest runs will accumulate secrets, unlike the `testSecretName`
created in `beforeAll` (331–347) which is explicitly deleted in `afterAll` at 391–395.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/smoketests/object-oriented/gateway-config.test.ts
**Line:** 423:432
**Comment:**
	*Resource Leak: This test creates a secret through the gateway but never deletes it, which leaks resources across repeated smoke-test runs and can eventually hit account limits. Add cleanup in a `finally` block so the secret is deleted even after assertions.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Comment on lines +437 to +448

expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(blueprintName);
const createResult = await curlRequest('POST', '/v1/blueprints', {
body: JSON.stringify({
name: blueprintName,
system_setup_commands: ['echo "test"'],
}),
contentType: 'application/json',
});

test('GET request with query parameters', async () => {
const { httpCode, responseBody } = await curlRequest(
'GET',
'/v1/devboxes?limit=2&status=running',
);
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(blueprintName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This test creates a blueprint but does not delete it afterward, leaving orphaned blueprints in the account and causing quota/resource buildup over time. Track the created id and delete it in a finally block. [resource leak]

Severity Level: Major ⚠️
- ⚠️ Smoketest runs accumulate unused blueprints in the Runloop account.
- ⚠️ May exhaust blueprint quotas or clutter admin dashboards.
- ⚠️ Increases need for manual cleanup of test artifacts.
Suggested change
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(blueprintName);
const createResult = await curlRequest('POST', '/v1/blueprints', {
body: JSON.stringify({
name: blueprintName,
system_setup_commands: ['echo "test"'],
}),
contentType: 'application/json',
});
test('GET request with query parameters', async () => {
const { httpCode, responseBody } = await curlRequest(
'GET',
'/v1/devboxes?limit=2&status=running',
);
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
expect(created.name).toBe(blueprintName);
let blueprintId: string | undefined;
try {
const createResult = await curlRequest('POST', '/v1/blueprints', {
body: JSON.stringify({
name: blueprintName,
system_setup_commands: ['echo "test"'],
}),
contentType: 'application/json',
});
expect(createResult.httpCode).toBe(200);
const created = JSON.parse(createResult.responseBody);
blueprintId = created.id;
expect(created.name).toBe(blueprintName);
} finally {
if (blueprintId) {
await curlRequest('DELETE', `/v1/blueprints/${encodeURIComponent(blueprintId)}`).catch(() => {});
}
}
Steps of Reproduction ✅
1. Enable smoketests with `RUN_SMOKETESTS=1` so the `comprehensive gateway proxying tests`
suite at `tests/smoketests/object-oriented/gateway-config.test.ts:282` is active.

2. Run the Jest suite so `beforeAll` (lines 331–377) provisions the gateway/devbox and
`curlRequest` helper (291–329) is available for HTTP calls through the gateway.

3. Let the test `POST request with JSON body - create blueprint` at lines 435–449 execute;
it sends a POST to `/v1/blueprints` via `curlRequest`, receives a 200 response, parses
`created`, and asserts `created.name` matches `blueprintName`.

4. Note that unlike other tests that explicitly clean created resources (e.g., the secret
in `special characters in URL path and query params` at 597–607), this blueprint test has
no corresponding DELETE call or `sdk` cleanup; each smoketest run leaves another blueprint
in the remote account.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/smoketests/object-oriented/gateway-config.test.ts
**Line:** 437:448
**Comment:**
	*Resource Leak: This test creates a blueprint but does not delete it afterward, leaving orphaned blueprints in the account and causing quota/resource buildup over time. Track the created id and delete it in a `finally` block.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

const httpCode = parseInt(httpCodeLine.replace('HTTP_CODE:', ''), 10);

expect(httpCode).toBeGreaterThanOrEqual(400);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The unauthorized-request test currently passes on any 4xx/5xx status, so server errors can be misclassified as successful auth behavior. Restrict this assertion to client-auth failure codes only. [logic error]

Severity Level: Major ⚠️
- ⚠️ Auth regression returning 5xx could pass smoketests unnoticed.
- ⚠️ Reduces reliability of unauthorized-access behavior coverage.
Suggested change
});
expect(httpCode).toBeLessThan(500);
Steps of Reproduction ✅
1. Enable smoketests with `RUN_SMOKETESTS=1` so `comprehensive gateway proxying tests` at
`tests/smoketests/object-oriented/gateway-config.test.ts:282` is executed.

2. Run the Jest file so the `unauthorized request without token fails` test at lines
492–502 runs; it calls `devbox!.cmd.exec` with a `curl` command that omits the
`Authorization` header against `${gatewayUrl}/v1/devboxes?limit=1`.

3. The test parses the HTTP status code from the `curl` output (lines 496–499) and
currently asserts only `expect(httpCode).toBeGreaterThanOrEqual(400);` at 501.

4. If the gateway or backend mistakenly responds with a 5xx (e.g., 500) instead of a
client-auth error (4xx), this test will still pass, treating the server error as
acceptable unauthorized behavior; by contrast, the nearby `invalid JSON body returns
error` test at 482–490 explicitly constrains to 4xx using both `>=400` and `<500`, showing
that the narrower assertion is the intended pattern.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/smoketests/object-oriented/gateway-config.test.ts
**Line:** 502:502
**Comment:**
	*Logic Error: The unauthorized-request test currently passes on any 4xx/5xx status, so server errors can be misclassified as successful auth behavior. Restrict this assertion to client-auth failure codes only.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai

codeant-ai Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI finished reviewing your PR.

@github-actions

github-actions Bot commented Mar 31, 2026

Copy link
Copy Markdown

✅ Object Smoke Tests & Coverage Report

Test Results

✅ All smoke tests passed

Coverage Results

Metric Coverage Required Status
Functions 100% 100%
Lines 90.21% - ℹ️
Branches 69.59% - ℹ️
Statements 89.15% - ℹ️

Coverage Requirement: 100% function coverage (all public methods must be called in smoke tests)

✅ All tests passed and all object methods are covered!

View detailed coverage report
File Functions Lines Branches
src/sdk.ts ✅ 100% 86.11% 72.58%
src/sdk/agent.ts ✅ 100% 100% 100%
src/sdk/axon.ts ✅ 100% 93.75% 100%
src/sdk/blueprint.ts ✅ 100% 100% 80%
src/sdk/devbox.ts ✅ 100% 91.96% 94.28%
src/sdk/execution-result.ts ✅ 100% 92.68% 70.83%
src/sdk/execution.ts ✅ 100% 95.65% 87.5%
src/sdk/gateway-config.ts ✅ 100% 100% 100%
src/sdk/mcp-config.ts ✅ 100% 100% 100%
src/sdk/network-policy.ts ✅ 100% 100% 100%
src/sdk/scenario-builder.ts ✅ 100% 98.46% 80.7%
src/sdk/scenario-run.ts ✅ 100% 96.87% 50%
src/sdk/scenario.ts ✅ 100% 100% 100%
src/sdk/scorer.ts ✅ 100% 100% 100%
src/sdk/secret.ts ✅ 100% 100% 100%
src/sdk/snapshot.ts ✅ 100% 100% 100%
src/sdk/storage-object.ts ✅ 100% 80% 48.93%

📋 View workflow run

@james-rl

james-rl commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

This looks ok but there's a lot of extra surface area to this PR that's making it hard to read.

@sid-rl
sid-rl force-pushed the sid/oo-sdk-axon-list-params branch 2 times, most recently from 7e9e5a1 to ac132c3 Compare April 1, 2026 01:36
@sid-rl
sid-rl merged commit 857ab06 into next Apr 1, 2026
8 checks passed
@sid-rl
sid-rl deleted the sid/oo-sdk-axon-list-params branch April 1, 2026 17:00
@stainless-app stainless-app Bot mentioned this pull request Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants